import random
from deap import creator, base, tools, algorithms
from tqdm import tqdm

creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

toolbox = base.Toolbox()

toolbox.register("attr_bool", random.randint, 0, 1)

print(toolbox.attr_bool())
print(random.randint(0, 1))

toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, n=100)
print(toolbox.individual(n=10), type(toolbox.individual(n=10)))  # <class 'deap.creator.Individual'>

toolbox.register("population", tools.initRepeat, list, toolbox.individual)
pp = toolbox.population(n=7)
print(len(pp), len(pp[0]), type(pp))  # 7 100, <class 'list'>


def evalOneMax(individual):
    return sum(individual),


toolbox.register("evaluate", evalOneMax)
toolbox.register("select", tools.selTournament, tournsize=3)

# mate & mutate in varAnd
# meth:`mate` for crossover, :meth:`mutate` for mutation
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)


population = toolbox.population(n=300)

NGEN = 40
for gen in tqdm(range(NGEN)):
    offspring = algorithms.varAnd(population, toolbox, cxpb=0.5, mutpb=0.1)
    fits = toolbox.map(toolbox.evaluate, offspring)
    for fit, ind in zip(fits, offspring):
        ind.fitness.values = fit
    population = toolbox.select(offspring, k=len(population))
top10 = tools.selBest(population, k=10)

print(top10)
